﻿// *---------------------------------------------------------------------------------------------------------*
// Solution:         JwikIDE									
// Project:           JwiKIDE								
// Source File:    NativeFile.cs									
// *---------------------------------------------------------------------------------------------------------*
// 
// © 2012 Digital Six Labs, LLC All Rights Reserved
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
// and associated documentation files (the "Software"), to deal in the Software without restriction, 
// including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 
// and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 
// subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in all copies or substantial 
// portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// 
// 
// 
// 
namespace JwiKIDE.JavaClassFileClasses
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;

    public class NativeClass
    {
        public string ClassName { get; set; }

        public int ClassId { get; set; }
    }

    public class NativeMethod
    {
        public string ClassName { get; set; }

        public string MethodName { get; set; }

        public string MethodType { get; set; }

        public int MethodId { get; set; }
    }

    public class NativeField
    {
        public string ClassName { get; set; }

        public string FieldName { get; set; }

        public string FieldType { get; set; }

        public int FieldId { get; set; }
    }


    /// <summary>
    /// TODO: Update summary.
    /// </summary>
    public class NativeFile
    {
        public List<NativeClass> NativeClasses { get; set; }

        public List<NativeMethod> NativeMethods { get; set; }

        public List<NativeField> NativeFields { get; set; }

        public int LowestNativeClassId { get; private set; }

        public NativeFile()
        {
            NativeClasses = new List<NativeClass>();
            NativeMethods = new List<NativeMethod>();
            NativeFields = new List<NativeField>();
            LowestNativeClassId = int.MaxValue;
        }

        public bool MethodIsNative(string className, string methodName, string methodType)
        {
            return this.NativeMethods.Any(method => className == method.ClassName && methodName == method.MethodName && methodType == method.MethodType);
        }

        public int GetMethodId(string className, string methodName, string methodType)
        {
            foreach (NativeMethod method in this.NativeMethods.Where(method => method.ClassName == className
                                                                          && method.MethodName == methodName
                                                                          && method.MethodType == methodType))
            {
                return method.MethodId;
            }
            return -1;
        }

        public int GetFieldId(string className, string fieldName, string fieldType)
        {
            foreach (NativeField field in this.NativeFields.Where(field => field.ClassName == className
                                                                      && field.FieldName == fieldName
                                                                      && field.FieldType == fieldType))
            {
                return field.FieldId;
            }
            return -1;
        }
        public int GetClassId(string className)
        {
            foreach (NativeClass nClass in this.NativeClasses.Where(nClass => nClass.ClassName == className))
            {
                return nClass.ClassId;
            }
            return -1;
        }
        public void Load(string className)
        {
            using (var fs = new FileStream(className, FileMode.Open))
            {
                TextReader reader = new StreamReader(fs);
                var nativeClassName = string.Empty;
                int nativeClassId = 0;
                while(reader.Peek()!=-1)
                {
                    var s = reader.ReadLine();


                    // obviously, if s is null, we do nothing.  If it starts with a #, we ignore it.
                    if(s != null && !s.StartsWith("#") && !s.StartsWith("//"))
                    {
                        var tokens = s.Split(new[] { ' ' });

                        if(s.Length>0)
                        {
                            switch(tokens[0].ToLower())
                            {
                                case "class":
                                    var newClass = new NativeClass { ClassName = tokens[1], ClassId = int.Parse(tokens[2]) };
                                    NativeClasses.Add(newClass);
                                    nativeClassName = tokens[1];
                                    nativeClassId = newClass.ClassId;
                                    if (nativeClassId < LowestNativeClassId) LowestNativeClassId = nativeClassId;
                                    break;
                                case "field":
                                    var substr = tokens[1].Split(new[] { ':' });
                                    int fid= int.Parse(tokens[2]);
                                    fid += nativeClassId << 8;
                                    var newField = new NativeField
                                        {
                                            ClassName = nativeClassName,
                                            FieldId = fid,
                                            FieldName = substr[0],
                                            FieldType = substr[1]
                                        };
                                    NativeFields.Add(newField);
                                    break;
                                case "method":
                                    var substr2 = tokens[1].Split(new[] { ':' });
                                    int mid = int.Parse(tokens[2]);
                                    mid += nativeClassId << 8;
                                    var newMethod = new NativeMethod
                                        {
                                            ClassName = nativeClassName, 
                                            MethodId = mid,
                                            MethodName=substr2[0],
                                            MethodType = substr2[1]
                                        };
                                    NativeMethods.Add(newMethod);
                                    break;
                            }
                        }

                    }
                }
            }
        }
    }
}
